"""Flask Web应用主程序
提供用户界面、任务管理API和统计看板
"""
from flask import Flask, render_template, request, jsonify, redirect, url_for, flash
from flask_login import LoginManager, current_user, login_required
from flask_cors import CORS
from flask_migrate import Migrate
from flask_socketio import SocketIO, emit, join_room, leave_room
import sys
import os
import time

# 添加项目根目录到路径
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__))))

from config.config import get_config
from services.shared.models import db
from services.shared.models.user import User
from services.shared.celery_app import celery_app
from services.web.auth import auth_bp
from services.web.api import api_bp, log_api_call
from services.web.dashboard import dashboard_bp
from services.web.routes.notification import notification_bp


def create_app(config_name=None):
    """应用工厂函数"""
    # 设置模板文件夹为项目根目录下的templates
    import os
    template_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'templates')
    static_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'static')
    
    app = Flask(__name__, template_folder=template_dir, static_folder=static_dir)
    
    # 加载配置
    if config_name:
        from config.config import config
        app.config.from_object(config[config_name])
    else:
        config_class = get_config()
        app.config.from_object(config_class)
    
    # 设置 SQLAlchemy 数据库 URI
    app.config['SQLALCHEMY_DATABASE_URI'] = app.config.get('DATABASE_URL')
    
    # 初始化扩展
    socketio = init_extensions(app)
    
    # 注册蓝图
    register_blueprints(app)
    
    # 注册错误处理器
    register_error_handlers(app)
    
    # 初始化数据库表（仅在需要时）
    with app.app_context():
        from services.shared.database import create_admin_user
        # 创建表（如果不存在）
        db.create_all()
        # 创建默认管理员账户
        create_admin_user()
        
        # 执行系统启动时的任务状态检查 - 已禁用，防止将正常任务标记为失败后又触发新任务
        # try:
        #     from services.shared.startup_task_checker import run_startup_task_check
        #     import threading
        #     import time
        #     
        #     def delayed_startup_check():
        #         """延迟执行启动检查，确保所有服务都已启动"""
        #         time.sleep(5)  # 等待5秒确保Celery等服务启动
        #         try:
        #             result = run_startup_task_check()
        #             if result['success']:
        #                 app.logger.info(f"启动任务状态检查完成，修正了 {result.get('fixed_count', 0)} 个任务")
        #             else:
        #                 app.logger.error(f"启动任务状态检查失败: {result.get('error', 'Unknown error')}")
        #         except Exception as e:
        #             app.logger.error(f"启动任务状态检查异常: {str(e)}")
        #     
        #     # 在后台线程中执行检查，避免阻塞应用启动
        #     check_thread = threading.Thread(target=delayed_startup_check, daemon=True)
        #     check_thread.start()
        #     
        # except Exception as e:
        #     app.logger.warning(f"启动任务状态检查初始化失败: {str(e)}")
    
    # 配置Celery
    celery_app.conf.update(app.config)
    
    # 注册WebSocket事件处理器
    register_socketio_events(socketio)
    
    # 初始化WebSocket服务
    from services.shared.websocket_service import get_websocket_service
    websocket_service = get_websocket_service()
    websocket_service.init_socketio(socketio)
    
    return app, socketio


def init_extensions(app):
    """初始化Flask扩展"""
    # 数据库
    from services.shared.database import migrate
    db.init_app(app)
    
    # 数据库迁移
    migrate.init_app(app, db)
    
    # 跨域支持
    CORS(app)
    
    # WebSocket支持
    socketio = SocketIO(
        app, 
        cors_allowed_origins="*", 
        async_mode='threading',
        logger=True,
        engineio_logger=True,
        always_connect=True
    )
    
    # 用户登录管理
    login_manager = LoginManager()
    login_manager.init_app(app)
    login_manager.login_view = 'auth.login'
    login_manager.login_message = '请先登录以访问此页面。'
    login_manager.login_message_category = 'info'
    
    @login_manager.user_loader
    def load_user(user_id):
        return User.query.get(int(user_id))
    
    return socketio


def register_blueprints(app):
    """注册蓝图"""
    # 认证蓝图
    app.register_blueprint(auth_bp, url_prefix='/auth')
    
    # API蓝图
    app.register_blueprint(api_bp, url_prefix='/api')
    
    # 仪表板蓝图
    app.register_blueprint(dashboard_bp, url_prefix='/dashboard')
    
    # 通知蓝图
    app.register_blueprint(notification_bp)
    
    # 公共方法蓝图
    from .routes.common_methods import common_methods_bp
    app.register_blueprint(common_methods_bp, url_prefix='/dashboard')
    
    # 主页路由
    @app.route('/')
    @log_api_call
    def index():
        if current_user.is_authenticated:
            return redirect(url_for('dashboard.overview'))
        return redirect(url_for('auth.login'))
    
    # 健康检查路由
    @app.route('/api/health')
    @log_api_call
    def health_check():
        return jsonify({
            'success': True,
            'status': 'ok',
            'service': 'web',
            'redis': check_redis_connection(),
            'celery': check_celery_status()
        })


def register_error_handlers(app):
    """注册错误处理器"""
    @app.errorhandler(404)
    def page_not_found(e):
        return render_template('errors/404.html'), 404
    
    @app.errorhandler(500)
    def internal_server_error(e):
        return render_template('errors/500.html'), 500


def check_redis_connection():
    """检查Redis连接状态"""
    try:
        from redis import Redis
        from config.config import get_config
        config = get_config()
        redis_client = Redis.from_url(config.REDIS_URL)
        redis_client.ping()
        return True
    except Exception as e:
        return False


def check_celery_status():
    """检查Celery状态"""
    try:
        # 尝试ping Celery workers
        response = celery_app.control.ping(timeout=1.0)
        return len(response) > 0
    except Exception as e:
        return False


def register_socketio_events(socketio):
    """注册WebSocket事件处理器"""
    from flask_socketio import emit, join_room, leave_room
    from flask_login import current_user
    import logging
    
    logger = logging.getLogger(__name__)
    logger.info(f"=== 注册WebSocket事件处理器到SocketIO实例: {socketio} ===")
    
    @socketio.on('connect')
    def handle_connect():
        """WebSocket连接事件"""
        from flask import request
        logger.info(f'=== WebSocket连接事件触发 ===')
        logger.info(f'WebSocket客户端连接: {request.sid}')
        
        # 允许所有连接
        return True
    
    logger.info(f"已注册 connect 事件处理器: {handle_connect}")
    
    @socketio.on('disconnect')
    def handle_disconnect():
        """客户端断开连接事件"""
        from flask import request
        logger.info(f'WebSocket客户端断开连接: {request.sid}')
    
    @socketio.on('join')
    def handle_join(room_name):
        """通用的加入房间事件"""
        from flask import request
        logger.info(f'收到join请求，房间: {room_name}，客户端: {request.sid}')
        
        if room_name:
            # 加入房间
            join_room(room_name)
            
            emit('joined', {'room': room_name})
            
            logger.info(f'客户端 {request.sid} 加入房间: {room_name}')
        else:
            logger.warning('join请求缺少房间名称')

    @socketio.on('join_execution')
    def handle_join_execution(data):
        """加入执行记录房间，接收实时更新"""
        from flask import request
        execution_id = data.get('execution_id')
        logger.info(f'收到join_execution请求: {data}')
        
        if execution_id:
            room_name = f'execution_{execution_id}'
            logger.info(f'尝试加入房间: {room_name}')
            
            # 尝试加入房间
            join_room(room_name)
            
            emit('joined_execution', {'execution_id': execution_id})
            
            logger.info(f'客户端加入执行记录房间: {room_name}')
        else:
            logger.warning('join_execution请求缺少execution_id')
    
    logger.info(f"已注册 join_execution 事件处理器: {handle_join_execution}")
    
    @socketio.on('leave_execution')
    def handle_leave_execution(data):
        """离开执行记录房间"""
        execution_id = data.get('execution_id')
        logger.info(f'收到leave_execution请求: {data}')
        if execution_id:
            room_name = f'execution_{execution_id}'
            leave_room(room_name)
            emit('left_execution', {'execution_id': execution_id})
            logger.info(f'用户离开执行记录房间: {room_name}')
        else:
            logger.warning('leave_execution请求缺少execution_id')


# 创建应用实例和socketio实例
app, socketio = create_app()

if __name__ == '__main__':
    config = get_config()
    # 使用配置文件中的WEB_SERVICE_PORT
    socketio.run(
        app,
        host='0.0.0.0',
        port=config.WEB_SERVICE_PORT,
        debug=app.config.get('DEBUG', False),
        allow_unsafe_werkzeug=True
    )